use std::collections::HashMap;

use serde::Deserialize;

use crate::{address::NetLocation, option_util::{NoneOrOne, NoneOrSome, OneOrSome}};


#[derive(Debug,Deserialize)]
pub enum Config {
    Server(ServerConfig),
    ClientConfigGroup{
        client_group: String,
        client_proxies: OneOrSome<ClientConfig>,
    },
    RuleConfigGroup{
        rule_config: String,
        rules: OneOrSome<RuleConfig>,
    },
}

#[derive(Debug,Deserialize)]
pub struct ServerConfig {
    pub bind_location: BindLocation,
    pub protocol: ServerProxyConfig,
    pub transport: Transport,
    pub tcp_settings: Option<TcpConfig>,
    pub quic_settings: Option<ServerQuicConfig>,
    pub rules: NoneOrSome<ConfigSelection<RuleConfig>>,
}

#[derive(Debug,Deserialize)]
pub enum ConfigSelection<T> {
    Config(T),
    GroupName(String),
}

#[derive(Debug,Deserialize)]
pub enum ServerProxyConfig {

}

#[derive(Debug,Deserialize)]
pub struct ServerQuicConfig {

}

#[derive(Debug,Deserialize)]
pub struct ClientConfig {
    pub bind_interface: NoneOrOne<String>,
    #[serde(default = "unspecified_address")]
    pub address: NetLocation,
    pub protocol: ClientProxyConfig,
    pub transport: Transport,
    pub tcp_settings: Option<TcpConfig>,
    pub quic_settings: Option<ClientQuicConfig>,
}

impl Default for ClientConfig {
    fn default() -> Self {
        Self {  }
    }
}

#[derive(Debug,Deserialize)]
pub struct RuleConfig {

}

#[derive(Debug,Deserialize)]
pub enum BindLocation {
    
}

#[derive(Debug,Deserialize)]
pub enum Transport {
    
}

#[derive(Debug,Deserialize)]
pub struct TcpConfig{

}

/*
load config file
*/
pub async fn load_configs(args: &Vec<String>) -> std::io::Result<Vec<ServerConfig>>{
    let mut all_configs = vec![];
    for config_filename in args {
        let config_bytes = match tokio::fs::read(config_filename).await{
            Ok(b) => b,
            Err(e) => {
                return Err(std::io::Error::new(
                    std::io::ErrorKind::InvalidInput,
                    format!("Could not read config file {}: {}",config_filename,e) 
                ));
            },
        };
        let confit_str = match String::from_utf8(config_bytes) {
            Ok(s) => s,
            Err(e) => {
                return Err(std::io::Error::new(
                    std::io::ErrorKind::InvalidInput,
                    format!("Could not parse config file {}: {}",config_filename,e)
                ));
            },
        };
        let mut configs = match serde_yaml::from_str::<Vec<Config>>(&confit_str) {
            Ok(c) => c,
            Err(e) => {
                return Err(std::io::Error::new(
                    std::io::ErrorKind::InvalidInput,
                    format!("Could not parse config file {} as config YAML: {}",config_filename,e)));
            },
        };
        all_configs.append(&mut configs);
    };

    let mut client_groups: HashMap<String,Vec<ClientConfig>> = HashMap::new();
    client_groups.insert(String::from("direct"), vec![ClientConfig::default()]); 

    let server_configs: Vec<ServerConfig> = vec![]; 
    Ok(server_configs)
}